gusucode.com > 黑白棋 V1.0 试用网络版源代码C++源码程序 > 黑白棋 V1.0 试用网络版源代码/BWChess/03D407_庞长才_PROJECT作业/BWChess钻石版/BWChessDlg.cpp

    // BWChessDlg.cpp : implementation file
#include "stdafx.h"
#include <math.h>
#include <mmsystem.h>//播放声音的头文件
#include "BWChess.h"
#include "SetupDlg.h"
#include "AboutDlg.h"
#include "Globalvar0.h"
#include "HelperAPI.h" //定义了3个对话框函数
#include "BWChessDlg.h"
#include "RecorDdlg.h"
#include "BestDlg.h"
#include <time.h>
#include "SettingDlg.h"
#include "Demo.h"
#include "windows.h"
#include "Message1.h"
#include "ip1.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CBWChessDlg dialog
BOOL PlaySounds(UINT IDSoundRes, WORD wFlag)//播放声音
{  //PlaySound 是标准函数<win.h>             
	if (g_bSoundOn)
		if (PlaySound(MAKEINTRESOURCE(IDSoundRes),//播放的声音资源
			AfxGetInstanceHandle(),//指明实例
			wFlag|SND_RESOURCE|SND_NODEFAULT))//标志位:不默认,使用实例包含的资源
			return TRUE;
	return FALSE;
}

CBWChessDlg::CBWChessDlg(CWnd* pParent ): CDialog(IDD_BWCHESS_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);//载入图标 to m_hIcon ,不载入则使用默认图标
	m_pMenu = new CMenu();//菜单
	m_PaintNum=0;
	hAccelerator=::LoadAccelerators(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_ACC));
    //载入加速键
	g_nCanHintTimeB= 3;
	g_nCanHintTimeW= 3;
	g_nStrollSpeed= 2;
	//获得时间和速度
	g_nStrollSpeed=abs(g_nStrollSpeed);
	g_nStrollSpeed%=3;//速度分为3种:低 中 高
	g_nCanHintTimeB=abs(g_nCanHintTimeB);
	g_nCanHintTimeB%=31;
	if(g_nCanHintTimeB<3)
		g_nCanHintTimeB=3;
	g_nCanHintTimeW=abs(g_nCanHintTimeW);
	g_nCanHintTimeW%=31;
	if(g_nCanHintTimeW<3)
	  g_nCanHintTimeW=3;
    //读注册表(关于英雄榜)
	g_nTime1		=AfxGetApp()->GetProfileInt(pSettings, _T("Time1"), 0);    
	g_nTime2		=AfxGetApp()->GetProfileInt(pSettings, _T("Time2"), 0);    
	g_nTime3		=AfxGetApp()->GetProfileInt(pSettings, _T("Time3"), 0);
	g_nMark1		=AfxGetApp()->GetProfileInt(pSettings, _T("Mark1"), 0);    
	g_nMark2		=AfxGetApp()->GetProfileInt(pSettings, _T("Mark2"), 0);    
	g_nMark3		=AfxGetApp()->GetProfileInt(pSettings, _T("Mark3"), 0);    
	g_strName1		=AfxGetApp()->GetProfileString(pSettings, _T("Name1"), _T("Anonymous"));    
	g_strName2		=AfxGetApp()->GetProfileString(pSettings, _T("Name2"), _T("Anonymous"));    
	g_strName3		=AfxGetApp()->GetProfileString(pSettings, _T("Name3"), _T("Anonymous"));
	//写入注册表(关于英雄榜)
	CString str;
	str.LoadString (IDS_AUTHOR);//载入字符串 “庞长才  制作”
	AfxGetApp()->WriteProfileString(_T("Author"), _T("Shuker"), str);  
	AfxGetApp()->WriteProfileInt(pSettings, _T("Time1"), g_nTime1);    
	AfxGetApp()->WriteProfileInt(pSettings, _T("Time2"), g_nTime2);    
	AfxGetApp()->WriteProfileInt(pSettings, _T("Time3"), g_nTime3);  
	AfxGetApp()->WriteProfileInt(pSettings, _T("Mark1"), g_nMark1);    
	AfxGetApp()->WriteProfileInt(pSettings, _T("Mark2"), g_nMark2);    
	AfxGetApp()->WriteProfileInt(pSettings, _T("Mark3"), g_nMark3);    
	AfxGetApp()->WriteProfileString(pSettings, _T("Name1"), g_strName1);    
	AfxGetApp()->WriteProfileString(pSettings, _T("Name2"), g_strName2);    
	AfxGetApp()->WriteProfileString(pSettings, _T("Name3"), g_strName3); 	
}

CBWChessDlg::~CBWChessDlg()//释放资源
{   //以下为new对应的资源
	delete m_pMenu;
}

void CBWChessDlg::InitParams()
{
	for (int i=0; i<NUM;i++)
	    for (int j=0; j<NUM; j++)
	    	kernel[i][j] = 0;	//0 for none,1 for white,2 for black,棋盘的初态

	kernel[3][3]=kernel[4][4]=2;//开局的
	kernel[3][4]=kernel[4][3]=1;//     4颗子

	m_CurPt.x = m_CurPt.y =-1;//放子的位置(初态)

	num_black=2;//黑白子
	num_white=2;//的颗数

	m_PassedTime=0;//黑棋流逝的时间
	m_PassedTime0=0;//白棋流逝的时间
	m_bGameOver = FALSE;//游戏是否已经结束
	
	//m_byColor是本程序的核心变量!!!!!!!!!!!!!!!
	m_byColor = 0; //代表棋手的颜色,在使用之前代表前一个棋手的颜色,
	                //使用完之后代表当前棋手的颜色,因此使用之前要将其取反 1:黑 0:白
	m_Skip=0;//对方是否无子可下,即对方是否跳过不下
	g_nStoneNum=0;//格子的个数
	m_TimerOn=0;//时间是否在计数
	m_HintOnce=0;//是否提示
	m_PeekOnce=0;//是否查看可下棋的位置
	m_IsGameStart=0;//游戏是否已经开始
	m_ListInfo.ResetContent();//清空列表
	m_HintTime0=0;//白棋点击的次数
	m_HintTime1=0;//黑棋点击的次数
	ListInfo.destroy();//stack 类,清空信息空栈
	m_UndoPoint.Destroy();//undo类,清空悔棋信息空栈
}

void CBWChessDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBWChessDlg)
	//以下部分是将控件与变量联系起来
	DDX_Control(pDX, IDC_TIME_CHINESE0, m_Time0);//白棋用时
	DDX_Control(pDX, IDC_INFO, m_Info);//走棋信息
	DDX_Control(pDX, IDC_LISTINFO, m_ListInfo);//走棋信息列表
	DDX_Control(pDX, IDC_WNUM, m_Wnum);//白棋数目
	DDX_Control(pDX, IDC_TIME_CHINESE, m_Time);//黑棋用时
	DDX_Control(pDX, IDC_BNUM, m_Bnum);////黑棋数目
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBWChessDlg, CDialog)//消息映射函数
	//{{AFX_MSG_MAP(CBWChessDlg)
	ON_WM_PAINT()//窗口内画图
	ON_WM_LBUTTONDOWN() //鼠标左击                          	
	ON_COMMAND(IDM_NEW, OnNew)	 //菜		
	ON_COMMAND(IDM_EXIT, OnExit)   //单			
	ON_COMMAND(IDM_ABOUT, OnAbout)    //命令			
	ON_WM_SETCURSOR()
	ON_WM_QUERYDRAGICON()
	ON_WM_SYSCOMMAND()
	ON_WM_CONTEXTMENU()//弹出菜单
	ON_WM_TIMER()
	ON_COMMAND(IDM_UNDO, OnUndo)//以下全为菜单命令
	ON_COMMAND(IDM_BEST, OnBest)
	ON_COMMAND(IDM_HINT, OnHint)
	ON_COMMAND(IDM_CANPLACE, OnCanplace)
	ON_COMMAND(IDM_SETTING, OnSetting)
	ON_COMMAND(IDM_OPEN, OnOpen)
	ON_COMMAND(IDM_SAVE, OnSave)
	ON_COMMAND(IDM_SAVEINFO, OnSaveinfo)
	ON_COMMAND(IDM_DEMO, OnDemo)
	ON_COMMAND(ID_Onhost, OnHost)
	ON_COMMAND(ID_Onconnect, OnConnect)
	ON_COMMAND(ID_Unlink, OnUnlink)
	ON_COMMAND(IDM_REPLAY, OnReplay)
	//}}AFX_MSG_MAP
	ON_LBN_DBLCLK(IDC_LISTINFO , OnListDoubleClicked)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBWChessDlg message handlers

BOOL CBWChessDlg::OnInitDialog()
{
	 CDialog::OnInitDialog();
	 SetIcon(m_hIcon, TRUE);			// Set big icon,m_hIcon是图标变量
	 SetIcon(m_hIcon, FALSE);		// Set small icon
     CBitmap bitmap;
	 bitmap.LoadBitmap(IDB_EMPTY);
	 BITMAP bm;
     bitmap.GetBitmap(&bm);
     m_wStoneWidth=(unsigned short) bm.bmWidth;         //bmWidth,bm.bmHeight
     m_wStoneHeight=(unsigned short)bm.bmHeight;
     CBitmap bitmap1;
	 bitmap1.LoadBitmap(IDB_F1_2);
     bitmap1.GetBitmap(&bm);
     m_wFrameWidth=(unsigned short)bm.bmWidth;         //bmWidth,bm.bmHeight
     m_wFrameHeight=(unsigned short)bm.bmHeight;
    //获取系统的相关信息
	int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);
	int cyScreen = ::GetSystemMetrics(SM_CYSCREEN);
	int cxDlgFrame = ::GetSystemMetrics(SM_CXDLGFRAME);
	int cyDlgFrame = ::GetSystemMetrics(SM_CYDLGFRAME);
	int cxCaption = ::GetSystemMetrics(SM_CYCAPTION); 
	int cyMenu = ::GetSystemMetrics(SM_CYMENU);//系统菜单的宽度
	int nWidth = m_wFrameHeight*2+ m_wFrameWidth*8 + 2*cxDlgFrame;//根据位图和系统参数
	int nHeight = m_wFrameHeight*2+ m_wFrameWidth*8 + cxCaption + 2*cyDlgFrame + cyMenu;//确定界面的大下
	MoveWindow((cxScreen-nWidth-230)/2, (cyScreen-nHeight)/2,nWidth+230, nHeight+2);
			     //确定窗口的位置和大小,默认状态是响应重画消息
	TimeCount.Create(this,nWidth+ 20, 40  ,0,4);//时间和棋子计数控件(自定义)的创建,4代表4位数,0无效
	TimeCount0.Create(this,nWidth+20, 120 ,0,4);
	BCount.Create	(this,nWidth+ 34, 230 ,0,2);
	WCount.Create	(this,nWidth+ 34 ,310 ,0,2);
//	ShowNumber(1);static文本控件的位置和大小,以像素为单位,this的左上角为(0,0)
	m_Time.MoveWindow(nWidth+18  ,20  ,60,20);
	m_Time0.MoveWindow(nWidth+18 ,100 ,60,20);
	m_Bnum.MoveWindow(nWidth+18  ,210 ,60,20);
	m_Wnum.MoveWindow(nWidth+18  ,290 ,60,20);
	m_ListInfo.MoveWindow(nWidth+95,22,110,410);//列表
	m_Info.MoveWindow(nWidth+95,2,110,20);//m_Infostatic文本
	m_IsGameStart=1;//游戏是否开始
	//设置系统菜单
	CMenu* sysmenu=GetSystemMenu(FALSE);
	sysmenu->DeleteMenu(2,MF_BYPOSITION);
   	sysmenu->DeleteMenu(0,MF_BYPOSITION);
	sysmenu->DeleteMenu(2,MF_BYPOSITION);
	CString str;
	str.LoadString(IDS_TITLE_CHINESE);//IDS_TITLE_CHINESE:“黑白棋”
	SetWindowText(str);//设置标题
	m_pMenu->DestroyMenu();
	m_pMenu->LoadMenu(IDR_MENU_CHINESE);//载入主界面菜单
	SetMenu(m_pMenu);
	m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);//提示无效
	m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);//悔棋无效
	m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);//查看可以下子的地方无效
	m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED);//保存棋局无效
	m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);//导出走棋信息无效
	m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED);//重温棋局无效
	if(g_bTopMost)//最前面,不移动,不改变大小
		SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
	else//不是最前面
		SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
	m_wXNull = m_wFrameHeight+1;//9 //包括白线
	m_wYNull = m_wFrameHeight+1;//10
	m_Client.top = m_wYNull;//m_Client代表8*8棋盘
	m_Client.left = m_wXNull;
	m_Client.bottom =m_wYNull + NUM * m_wStoneHeight;
	m_Client.right =m_wXNull + NUM * m_wStoneWidth;
	int i,j;
	for (i=0; i<NUM;++i)
	    for (j=0; j<NUM; j++)
	    	kernel[i][j] = 0;	//0代表无子
	num_black=0;
	num_white=0;
	m_PassedTime=0;
	m_PassedTime0=0;
	m_TimerOn=0;
	m_HintOnce=0;//0 for have not hinted yet,1 for have hinted
	m_PeekOnce=0;
	m_HintTime0=0;
	m_HintTime1=0;
	m_bGameOver=TRUE;
	return TRUE;  // return TRUE  unless you set the focus to a control
}//end OnInitDialog

void CBWChessDlg::OnPaint() //游戏启动时作的一些准备工作
{
	CPaintDC dc(this); // device context for painting
	CDC * pdc=GetDC();
	if (IsIconic())//如果窗口已最小化,画图标(意义不大)
	{
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);//获取图标的大小,像素为单位
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);//获得画图区,并画图于窗口中间
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);//m_hIcon 代表图标
	}
	else//normal 大小
	{
		ShowNumber(1);//显示计数器控件
		DrawFrame(&dc);//显示棋盘边框
        BYTE t;
		if(!m_IsGameStart)//没开始                                                 
		{
			for (int i=0; i<NUM; ++i)
				for (int j=0; j<NUM; ++j)
				{
                    t=(unsigned char)(kernel[i][j]-1);
		    		if (kernel[i][j])//0 for none, 1 for white,2 for black,             
						PutStone(t, CPoint(j,i), &dc);//画棋盘 PutStone:画棋子
				}
			if(m_CurPt.x >=0)//m_CurPt.x/y 取0——7
			{
				int nX = m_CurPt.x*m_wStoneWidth + m_wXNull;//计算棋子的位置(nx,ny)
				int nY = m_CurPt.y*m_wStoneHeight + m_wYNull;
				int byColor= kernel[m_CurPt.y][m_CurPt.x]-1;//棋子的颜色 :白 黑
				if (byColor == 0)//白
					DrawBitmap(pdc,nX,nY,IDB_CURWHITE, SRCCOPY);
				else if (byColor == 1)//黑
					DrawBitmap(pdc,nX,nY,IDB_CURBLACK, SRCCOPY);
			}	//此处画棋子
		}//end if(!m_IsGameStart)

		if(m_HintOnce)//0 for have not hinted yet,1 for have hinted :m_HintOnce代表是否提示
		{
			COLORREF crColor = m_byColor ? RGB(255,255,255) : RGB(0,0,0);//确定颜色
			CPen pen(PS_SOLID, 2, crColor);
			CPen *pOldPen = dc.SelectObject(&pen);	//画 提示符 “X”
			dc.MoveTo(x1, y1);
			dc.LineTo(x2, y1);
			dc.LineTo(x2, y2);
			dc.LineTo(x1, y2);
			dc.LineTo(x1, y1);
			dc.LineTo(x2, y2);
			dc.MoveTo(x2, y1);
			dc.LineTo(x1, y2);//x1 y1 x2 y2 的初值?????
			dc.SelectObject(pOldPen);
		}
		if(m_PeekOnce)//代表是否查看可下的位置,画可下的位置
		{
			int px,py;
			int xx1,yy1;
			int length,hy;

			if(m_byColor)//黑
				length=wsp.isempty();
			else//白
				length=bsp.isempty();
			if(length)
				return;

			do
			{
				if(m_byColor)//从栈里取可放子的格子
					length=wsp.GetNextPos(&py,&px,&hy);//有效格子的个数
				else
					length=bsp.GetNextPos(&py,&px,&hy);
				xx1 = px*m_wStoneWidth + m_wXNull;//-4 + m_cxGrid / 2;
				yy1 = py*m_wStoneHeight + m_wYNull;//-4 + m_cyGrid / 2;
				if(m_byColor)//显示可放子的格子(显示一个标志性的位图)
					DrawBitmap(pdc,xx1,yy1,IDB_CANPLACE2, SRCCOPY);
				else
					DrawBitmap(pdc,xx1,yy1,IDB_CANPLACE1, SRCCOPY);
			}while(length);

			if(m_byColor)
				wsp.CopyBackIndex ();
			else
				bsp.CopyBackIndex ();
		}
		Mutex1.Lock();//互斥,在“Globalvar0.h”里定义的变量
		if(g_nIsDemo && g_nMutex)
		{
			g_nMutex=0;

			m_Mutex.Unlock();//互斥,在“Globalvar0.h”里定义的变量
		}
		Mutex1.Unlock();
	}
	ReleaseDC(pdc);
}//end paint


HCURSOR CBWChessDlg::OnQueryDragIcon()//返回图标
{
	return (HCURSOR) m_hIcon;//返回图标
}

void CBWChessDlg::OnLButtonDown(UINT nFlag, CPoint point)//左击
{       
	if(!ready)// P 操作!!!!!!!!
	   return;


	CPoint pt;
	if(!IsInPanel(point) || m_bGameOver || g_nIsDemo)
		return;//无效 返回

	
	
	//此处为非网络模式
	if (g_nRunMode != MODE_NETWORK&&PointToStonePos(point, pt))
	{
		int nX = pt.x;
		int nY = pt.y;
		if (kernel[nY][nX]==0) //此处无子     
		{
			if (g_nRunMode == MODE_WITH_COMPUTER)//模式是与计算机对弈
			{
		 		if ((g_bUserBlack && !m_byColor) || 
	 				(!g_bUserBlack && m_byColor)) //数据正确
				{                                    
					// User
					m_byColor = !m_byColor;	// 0-Black  1-White//设置当前棋手的颜色,因为初值为黑色棋手,
					                                  //但是m_byColor==0,代表白色,所以要先设成黑色
					//undo
					duplicate();//保存副本
					//end undo
					if(BtoW(nY,nX,m_byColor+1))//将棋盘上被夹住的子变色
					{
						m_HintOnce=0;
						m_PeekOnce=0;
						m_CurPt=pt;
						AddStringToList(nY,nX,m_byColor);//将信息加入列表框
						InvalidateRect(m_Client, FALSE);//刷新窗口
						UpdateWindow();//显示窗口
						PlaySounds(IDSOUND_PUTSTONE);   
						Ring(IsEnd(!m_byColor+1));//根据棋盘的状态处理善后工作
						// -1 for both
        //棋盘的状态: // 0 for the int have no position
                      //1 for the int have one position ,no use now
                     //return 2 for have more than one
		//函数原型:int CBWChessDlg::IsEnd(int whogo);
         //whogo :1代表黑色,2代表白色
						// Computer                       
						if (!m_bGameOver && !m_Skip)
						{
							do
							{
								m_byColor = !m_byColor;			// 1-Black  0-White
								int ptBest_x,ptBest_y;
								//undo
								duplicate();//保存副本
								//end undo
								Place(&ptBest_x,&ptBest_y,m_byColor+1);//计算机寻找最佳位置
								//函数原型:void Place(int *x, int *y,int color,int nSkill)
								//color: 1 白 2 黑 
								BtoW(ptBest_x,ptBest_y,m_byColor+1);//将棋盘上被夹住的子变色
								CPoint pt;
								pt.x = ptBest_y*m_wStoneWidth + m_wXNull+m_wStoneWidth/2;
								pt.y = ptBest_x*m_wStoneHeight + m_wYNull+m_wStoneWidth/2;
								m_CurPt.x=ptBest_y;
								m_CurPt.y=ptBest_x;
								ClientToScreen(&pt);
								MoveCursor(pt.x, pt.y);//移动光标,此时m_byColor代表的是当前棋手的颜色
								InvalidateRect(m_Client, FALSE);
								UpdateWindow();//更新棋盘
								AddStringToList(ptBest_x,ptBest_y,m_byColor);//将信息加入列表框
								PlaySounds(IDSOUND_PUTSTONE);
								Ring(IsEnd(!m_byColor+1));//作善后处理,包括“游戏结束或对手无子可走”
							}while(m_Skip);//m_Skip==1表示对手无子可走,由计算机继续走
						}

						if(!m_bGameOver && g_bPeepOften)
							OnCanplace();//继续搜索
					}
					else//没有夹住任何棋子,撤消已有的操作
					{
						int temp[NUM*NUM];
						m_UndoPoint.pop(temp);
						m_byColor=!m_byColor;
						PlaySounds(IDSOUND_ERROR);
					}	
					
				}    //  end if ((g_bUserBlack && !m_byColor) ||(!g_bUserBlack && m_byColor)) 

			}// end  模式是与计算机对弈  

			else if (g_nRunMode == MODE_2PLAYER)// 人对人!!			// Users
			{
				m_byColor = !m_byColor;		// 1-Black  0-White,由当前棋手的ID取得当前棋手的颜色,
                                             //颜色与ID正好相反,故取反
				duplicate();
				if(BtoW(nY,nX,m_byColor+1))//有棋子可变色
				{
					m_HintOnce=0;//不提示
					m_PeekOnce=0;//不查看
					m_CurPt=pt;
					AddStringToList(nY,nX,m_byColor);
					InvalidateRect(m_Client,FALSE);
					UpdateWindow();
					PlaySounds(IDSOUND_PUTSTONE);        
					Ring(IsEnd(!m_byColor+1));
					if(!m_bGameOver && g_bPeepOften)
						OnCanplace();
				}
				else//没有夹住任何棋子,撤消已有的操作
				{
					int temp[NUM*NUM];
					m_UndoPoint.pop(temp);
					m_byColor=!m_byColor;
					PlaySounds(IDSOUND_ERROR);
				}
			}//end  人对人!!
			else ;//此情况非法!!

		}//end 此处无子	   
		
		else//有子
		PlaySounds(IDSOUND_ERROR);

	}//end “if (PointToStonePos(point, pt))”
	else  if (!PointToStonePos(point, pt))//无子
		PlaySounds(IDSOUND_ERROR);
	//此处为非网络模式
	
	
	////模式是网络模式
	if(Sever==0||Sever==1)//已连网
	if (g_nRunMode == MODE_NETWORK&&PointToStonePos(point, pt))
	{
		int nX = pt.x;
		int nY = pt.y;
		if (kernel[nY][nX]==0) //此处无子     
		{			
				if ((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor)) //数据正确
				{                                    
					m_byColor = !m_byColor;	// 0-Black  1-White//设置当前棋手的颜色,因为初值为黑色棋手,
					                                  //但是m_byColor==0,代表白色,所以要先设成黑色
					duplicate();//保存副本			
					if(BtoW(nY,nX,m_byColor+1))//将棋盘上被夹住的子变色
					{
						m_Mutex.Lock();
						m_HintOnce=0;
						m_PeekOnce=0;
						m_CurPt=pt;
						AddStringToList(nY,nX,m_byColor);//将信息加入列表框
						InvalidateRect(m_Client, FALSE);//刷新窗口
						UpdateWindow();//显示窗口
						PlaySounds(IDSOUND_PUTSTONE);   
						Ring(IsEnd(!m_byColor+1));//根据棋盘的状态处理善后工作
						//正确调用
						if(!m_bGameOver && g_bPeepOften)//m_Skip为1,显示自己的位置,否则显示对方的位置
						OnCanplace();
					     if(m_Skip==1)
						 ready=true;
				        else 
						 ready=false;
						if(m_bGameOver)
						ready=false;
                        if(m_bGameOver)
                        Senddata(nX,nY,CMD_OVER);//发数据给对方, V 操作!!!!!
						if(m_Skip==1)
                        Senddata(nX,nY,CMD_SKIP);//发数据给对方, V 操作!!!!!

                        Senddata(nX,nY,CMD_CLICK);//发数据给对方, V 操作!!!!!
						m_Mutex.Unlock();
                        
					}//end if(BtoW(nY,nX,m_byColor+1))
					else//没有夹住任何棋子,撤消已有的操作
					{
						int temp[NUM*NUM];
						m_UndoPoint.pop(temp);
						m_byColor=!m_byColor;
						PlaySounds(IDSOUND_ERROR);
					}	
				}    //  end if ((g_bUserBlack && !m_byColor) ||(!g_bUserBlack && m_byColor)) 
		}	   		
		
	}//此处为网络模式
    else if (!PointToStonePos(point, pt))//无子
		PlaySounds(IDSOUND_ERROR);//发出错误声音
	//以上为网络模式



	//将其它工作传给基类处理
	CDialog::OnLButtonDown(nFlag, point);
}    //end  OnLButtonDown        
          
int CBWChessDlg::Distance(const CPoint &pt1, const CPoint &pt2)//计算两点间的距离
{
	return (int)sqrt((double)(pt1.x-pt2.x)*(pt1.x-pt2.x) + (double)(pt1.y-pt2.y)*(pt1.y-pt2.y));
}

BOOL CBWChessDlg::IsStonePoint(CPoint& ptStone)//检查是否在棋格内
{
	if (ptStone.x<0 || ptStone.x>=NUM || ptStone.y<0 || ptStone.y>=NUM)
	{//不合法,矫正到最边缘
		if (ptStone.x<0)
			ptStone.x = 0;
		else if (ptStone.x>=NUM)
			ptStone.x = NUM-1;
		if (ptStone.y<0)
			ptStone.y = 0;
		else if (ptStone.y>=NUM)
			ptStone.y = NUM-1;
		return FALSE;
	}
	return TRUE;
}

BOOL CBWChessDlg::PointToStonePos(const CPoint &pt, CPoint& ptStone)//将客户区坐标转化为棋盘坐标
{
	int nPosX = (pt.x - m_wXNull-m_wStoneWidth/2)/m_wStoneWidth;//粗略计算棋盘坐标,有误差
	int nPosY = (pt.y - m_wYNull-m_wStoneWidth/2)/m_wStoneHeight;
	CPoint pt0(nPosX * m_wStoneWidth + m_wXNull+m_wStoneWidth/2, nPosY*m_wStoneHeight+m_wYNull+m_wStoneWidth/2);
	CPoint pt1((nPosX+1)*m_wStoneWidth+m_wXNull+m_wStoneWidth/2, nPosY*m_wStoneHeight+m_wYNull+m_wStoneWidth/2);
	CPoint pt2((nPosX+1)*m_wStoneWidth+m_wXNull+m_wStoneWidth/2, (nPosY+1)*m_wStoneHeight+m_wYNull+m_wStoneWidth/2);
	CPoint pt3(nPosX*m_wStoneWidth+m_wXNull+m_wStoneWidth/2, (nPosY+1)*m_wStoneHeight+m_wYNull+m_wStoneWidth/2);
	//四个参照点,选择误差最小的一点
	int nDis0 = Distance(pt, pt0);
	int nDis1 = Distance(pt, pt1);
	int nDis2 = Distance(pt, pt2);
	int nDis3 = Distance(pt, pt3);
	int nLimit = m_wStoneWidth/2-4;
	if (nDis0 <= nLimit)
		ptStone = CPoint(nPosX, nPosY);
	else if (nDis1 <= nLimit)
		ptStone = CPoint(nPosX+1, nPosY);
	else if (nDis2 <= nLimit)
		ptStone = CPoint(nPosX+1, nPosY+1);
	else if (nDis3 <= nLimit)
		ptStone = CPoint(nPosX, nPosY+1);
	else//不在棋盘内
	{
		int nMin1 = min(nDis0, nDis1);
		int nMin2 = min(nDis2, nDis3);
		int nMin = min(nMin1, nMin2);

		if (nMin == nDis0)
			ptStone = CPoint(nPosX, nPosY);
		else if (nMin == nDis1)
			ptStone = CPoint(nPosX+1, nPosY);
		else if (nMin == nDis2)
			ptStone = CPoint(nPosX+1, nPosY+1);
		else if (nMin == nDis3)
			ptStone = CPoint(nPosX, nPosY+1);

		IsStonePoint(ptStone);//矫正到棋盘上
		return FALSE;
	}
	return IsStonePoint(ptStone);
}

void CBWChessDlg::Ring(int m_nType)//处理走完一步棋之后的善后处理
{
	Calcu_BW();
	ShowNumber();
	m_Skip=0;//only when m_nType==0,then m_Skip==1;
				//other m_Skip==0;
	switch(m_nType)
	{
	case -1://游戏结束
		{
			int win=0;
			int addp=0;
			m_bGameOver = TRUE;
			if(m_TimerOn)
			{
				KillTimer(PASSEDTIME);
				m_TimerOn=0;
			}
			m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);
			m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);
			m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);
			m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_ENABLED);
			m_pMenu->EnableMenuItem(IDM_REPLAY,MF_ENABLED);
			CString str1,str2, str3,strPrompt;
			TCHAR str[64];

			str2.LoadString(IDS_TITLE_CHINESE);//“黑白棋”

			if(g_nRunMode == MODE_2PLAYER)//两人对战
			{
				if(num_white<num_black)
				{
					addp=2;
					str1.LoadString(IDS_BLACKWIN_CHINESE);//“本局黑棋胜。”
				}
				else if(num_white>num_black)
				{
					addp=1;
					str1.LoadString(IDS_WHITEWIN_CHINESE);//“本局白棋胜。”
				}
				else
				{
					addp=3;
					str1.LoadString(IDS_TIE_CHINESE);//“本局平手。\n我们的水平不分上下!”
				}
				str3.LoadString(IDS_END_CHINESE);//“黑棋%d子,白棋%d子。\n”
				
				wsprintf(str, str3.GetBuffer(256), num_black,num_white);
				strPrompt = str;
				strPrompt += str1; 
			}
			else//人机对战
			{
				g_nStoneNum=abs(num_black-num_white);
				g_nBestMark=abs((num_white+num_black)*(num_white-num_black));//计算得分,公式是|A*A-B*B|
				if(!(num_black && num_white))//吃光了,再加800
					g_nBestMark+=800;
				if(num_white>num_black)//白 胜
					addp=1;
				if(num_white<num_black)//黑 胜
					addp=2;
				if(num_white==num_black)//平局
				{
					str1.LoadString(IDS_TIE_CHINESE);//“本局平手。\n我们的水平不分上下!”
					win=1;
					addp=3;
				}
				else if((g_bUserBlack && (num_white>num_black)) || ((!g_bUserBlack) && (num_white<num_black)))
				{//人是输家
					if(!num_white || !num_black)
						str1.LoadString(IDS_COMPUTERWIN0_CHINESE);//“你的棋子被我全吃掉了!\n再去研究一下规则吧!”
					else if(g_nStoneNum>=40)//“你真是太差了,我胜了%d你手。\n回去多练几年吧!”
						str1.LoadString(IDS_COMPUTERWIN1_CHINESE);
					else//“我赢了。胜你%d手。\n你还不行,好好锻炼一下吧!”
						str1.LoadString(IDS_COMPUTERWIN2_CHINESE);
				}
				else if((g_bUserBlack && (num_white<num_black)) || ((!g_bUserBlack) && (num_white>num_black)))
				{//人是赢家
					win=1;
					if(!num_white || !num_black)//“你好厉害,居然把我的棋全吃掉了!\n佩服佩服!”
						str1.LoadString(IDS_USERWIN0_CHINESE);
					else if(g_nStoneNum<=6)//“恭喜,你获胜了。胜了我%d手。\n愿意再较量一盘吗?”
						str1.LoadString(IDS_USERWIN2_CHINESE);
					else//“你才胜了我%d手,我不服!\n有种再下一盘!”
						str1.LoadString(IDS_USERWIN1_CHINESE);
				}

				if(num_white!=num_black)
				{
					if(num_white && num_black)
					{
						wsprintf(str, str1.GetBuffer(256), g_nStoneNum);
						strPrompt=str;
					}
					else
						strPrompt=str1;
				}
				else
					strPrompt=str1;//载入胜负信息
			}// end人机对战

			AddStringToList(0,0,0,addp);//载入胜负信息与列表

			if(g_nRunMode == MODE_2PLAYER)//人人对战
				PlaySounds(IDSOUND_USERWIN);
			else//人机对战
				PlaySounds((win==0) ? IDSOUND_COMPUTERWIN : IDSOUND_USERWIN );

			MsgBox(strPrompt,str2);//弹出胜负的对话框

			BOOL bWinner = FALSE;
			if (g_nBestMark>g_nMark1)	    		
	    		bWinner = TRUE;//打破了记录
			
			if (g_nRunMode == MODE_WITH_COMPUTER && bWinner &&
	    		(win==1))//存储记录
			{
	    		CRecordDlg recordDlg;
//    			int result=
				recordDlg.DoModal();
//				if(result==IDOK)
//					OnBest();
			}
		}
		break;


	case 0://表示某一方不能下,m_Skip==1;由另外一方(m_byColor方:1黑,0白)继续下
		{
			CString str3,str2;
			if(g_nRunMode == MODE_WITH_COMPUTER)//人机对战
			{
				if((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor))
				//m_byColor代表应下棋的颜色,当棋手的颜色与m_byColor不匹配时表示当前棋手不能下
					str3.LoadString(IDS_USER_NOPLACE_CHINESE);//“你无处可走,只能让我走.”
				else if((g_bUserBlack && m_byColor) || (!g_bUserBlack && !m_byColor))
					str3.LoadString(IDS_COMPUTER_NOPLACE_CHINESE);//“我没法走了,只能让你走了.”
			}
			if(g_nRunMode == MODE_2PLAYER)//人人
			{
				if(!m_byColor)//该白色下,则黑色不能下
					str3.LoadString(IDS_BLACK_NOPLACE_CHINESE);//“黑棋无处可走。”
				else//该黑色色下
					str3.LoadString(IDS_WHITE_NOPLACE_CHINESE);//“白棋无处可走”
			}
			str2.LoadString(IDS_TITLE_CHINESE);
			MsgBox(str3,str2);
			//important type
			m_Skip=1;
			//
			m_byColor=!m_byColor;//由于:OnLButtonDown(UINT nFlag, CPoint point)每次在走棋之前,都会反色,
			//因此在此处先反色,确保走棋的正确
		}
		break;
	}
}

void CBWChessDlg::OnNew()//响应 “新棋盘” 菜单命令
{	
	int HaveKilled=0;
	if(m_TimerOn)//停止计时
	{
		HaveKilled=1;
		KillTimer(PASSEDTIME);
		m_TimerOn=0;
	}
    
	//备份数据
	int a=m_bGameOver;
	int b=g_nRunMode;

	CSetupDlg setupDlg;//创建设置对话框
	if (setupDlg.DoModal()==IDCANCEL)//取消了
	{
		if(HaveKilled)//恢复计时
		{			
			SetTimer(PASSEDTIME,1000,NULL);
			m_TimerOn=1;
		}
		return;
	}

     if(!a&&b==MODE_NETWORK)//当前游戏没有结束
	{
        Senddata(0,0,CMD_RESIGN);
        m_bGameOver=TRUE;
	}


       CString str;
	//对相关参数进行初始化
	if(g_nRunMode==MODE_WITH_COMPUTER)//人机0
	{
	     if (g_nRunMode==MODE_WITH_COMPUTER && !g_bUserBlack)
		 {	
	      str.LoadString(IDS_SINGLE_COMPUTER_CHINESE);//IDS_TITLE_CHINESE:“黑白棋”
	       SetWindowText(str);//设置标题
		 }
	    else
		{

	    str.LoadString(IDS_SINGLE_USER_CHINESE);//IDS_TITLE_CHINESE:“黑白棋”
	    SetWindowText(str);//设置标题
		}
		ready=1;
	}

  if(g_nRunMode==MODE_2PLAYER)//人人1
	{
		if(g_nIsNoTimeLimit)
		{
	        str.LoadString(IDS_DOUBLE_NOLIMIT_CHINESE);//IDS_TITLE_CHINESE:“黑白棋”
	        SetWindowText(str);//设置标题
		}
		else
		{
	        str.LoadString(IDS_DOUBLE_LIMIT_CHINESE);//IDS_TITLE_CHINESE:“黑白棋”
	        SetWindowText(str);//设置标题
		}
	    ready=1;
	}
  if(g_nRunMode==MODE_NETWORK)//网络2
	{
		
	  if(Sever==2)//非网络模式
		{
	        str.LoadString(IDS_NONETWORK);//IDS_TITLE_CHINESE:“黑白棋”
	        SetWindowText(str);//设置标题
		    AfxMessageBox("请先连上网络");
			return;
		}
		else if(Sever==1)
		{
	        str.LoadString(IDS_SERVER);//IDS_TITLE_CHINESE:“黑白棋”
	        SetWindowText(str);//设置标题
			g_bUserBlack = TRUE;//先手
			g_nSkill = 1;//棋力
			g_nTimeLimit=60;//允许等待的最大时间 from 60 to 9000,单位秒
            g_nIsNoTimeLimit=1;//限时
		    ready=1;
		}
        else if(Sever==0)
		 {
	        str.LoadString(IDS_CLIENT);//IDS_TITLE_CHINESE:“黑白棋”
	        SetWindowText(str);//设置标题
			g_bUserBlack = FALSE;//先手
			g_nSkill = 1;//棋力
			g_nTimeLimit=60;//允许等待的最大时间 from 60 to 9000,单位秒
            g_nIsNoTimeLimit=0;//限时
			ready=0;
		 }
	     else
		 {
			 AfxMessageBox("未知错误!");
		     return;
		 }
	}
  //以下部分是重新初始化
	InitParams();
	Invalidate();   
	UpdateWindow();   
	ShowNumber(1);
	SetChessTitle();
  //设置菜单
	m_pMenu->EnableMenuItem(IDM_HINT,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_UNDO,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);
	m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED);
	PlaySounds(IDSOUND_NEWGAME);
	UpdateWindow();
	SetWindowText(str);
    if (g_nRunMode==MODE_WITH_COMPUTER && !g_bUserBlack)//人机对站,机先走
	{// Computer first,SO Computer is black!!
		CPoint pt;            			
		m_byColor = !m_byColor;			// 1-Black  0-White,将前一对手的颜色变成当前对手的颜色
		int ptBest_x,ptBest_y;
		IsEnd(m_byColor+1);//是否结束
		Place(&ptBest_x,&ptBest_y,m_byColor+1);
		BtoW(ptBest_x,ptBest_y,m_byColor+1);
		AddStringToList(ptBest_x,ptBest_y,m_byColor);
		pt.x = ptBest_y*m_wStoneWidth + m_wXNull+m_wStoneWidth/2;
		pt.y = ptBest_x*m_wStoneHeight + m_wYNull+m_wStoneWidth/2;
		m_CurPt.x=ptBest_y;
		m_CurPt.y=ptBest_x;
		ClientToScreen(&pt);
		SetCursorPos(pt.x, pt.y);
		InvalidateRect(m_Client, FALSE);
		UpdateWindow();
		PlaySounds(IDSOUND_PUTSTONE);
	}  

	Ring(IsEnd(!m_byColor+1));
	if(!m_bGameOver && g_bPeepOften)
		OnCanplace();//显示位置

	SetTimer(PASSEDTIME,1000,NULL);
	m_TimerOn=1;
	m_nIsContinueReplay=1;
}

void CBWChessDlg::OnAbout()
{
    CAboutDlg aboutDlg(this);
    aboutDlg.DoModal();//响应“关于黑白棋”菜单
}

void CBWChessDlg::OnExit()//关闭程序
{
	if(m_TimerOn)
		KillTimer(PASSEDTIME);
	if(g_nIsDemo)
		::TerminateThread(m_CcThread->m_hThread,0);

	CDialog::EndDialog(0);
}

void CBWChessDlg::PutStone(BYTE byColor, const CPoint &point, CDC *pDC)//填充棋格
{                                      
	int nX = point.x*m_wStoneWidth + m_wXNull;                             
	int nY = point.y*m_wStoneHeight + m_wYNull;
	if (byColor == 0)//  0:  WHITE  1  :BLACK
		DrawBitmap(pDC,nX,nY,IDB_WHITE, SRCCOPY);
	else if (byColor == 1)
		DrawBitmap(pDC,nX,nY,IDB_BLACK, SRCCOPY);
}

BOOL CBWChessDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{//响应光标事件
	CPoint point, pt;
	::GetCursorPos(&point);
   	ScreenToClient(&point);
	if (PointToStonePos(point, pt) && !m_bGameOver && !g_nIsDemo)
	{	
		//在棋盘内,显示 IDC_WHITE_HAND:IDC_BLACK_HAND 型 光标
	                          //  0:  WHITE  1 : BLACK,m_byColor代表前一个棋手的颜色,即还没有更新
		::SetCursor(AfxGetApp()->LoadCursor(m_byColor ? IDC_WHITE_HAND:IDC_BLACK_HAND));
		return TRUE;
	}
  // 其他作默认处理
	return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

void CBWChessDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{
	if(nID == SC_CLOSE)
		OnExit();
	
	CDialog::OnSysCommand(nID, lParam);
}

void CBWChessDlg::OnContextMenu(CWnd* pWnd, CPoint point) //弹出菜单
{
	CRect rect;
	GetClientRect(&rect);
	CPoint pt=point;
	ScreenToClient(&pt);
	if(!rect.PtInRect (pt))//不在棋盘内
	{
		CDialog::OnContextMenu (pWnd,point);
		return;
	}
	if(g_nIsDemo)//正在演示(不会用到,因为此时互斥!)
		return;
	CMenu menu;
	menu.LoadMenu(IDR_MENU_CONTEXT_CHINESE);//载入菜单

	if(m_bGameOver)
	{
		menu.EnableMenuItem(IDM_UNDO, MF_GRAYED);   
		menu.EnableMenuItem(IDM_HINT, MF_GRAYED);   
		menu.EnableMenuItem(IDM_CANPLACE, MF_GRAYED);
		menu.EnableMenuItem(IDM_SAVEINFO,MF_ENABLED);
		menu.EnableMenuItem(IDM_REPLAY,MF_ENABLED);
	}
	if(!m_bGameOver)
	{
		menu.EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);
		menu.EnableMenuItem(IDM_REPLAY,MF_GRAYED);
	}
	if(m_IsGameStart)
		menu.EnableMenuItem(IDM_SAVE, MF_GRAYED);

    menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, 
										   point.x, point.y, this);//弹出菜单
}
////////////////////////// End of BWCHESS.CPP ////////////////////////////////

int CBWChessDlg::BtoW(int x1, int y1, int flag)//翻转棋子!!!
{ //x1 纵坐标  y1横坐标
	int yes;//if yes ==0 then there is no position to change
			//if yes==1 then there is any position to change
	int temp=flag;
	int x=0,y=0,i=0,j=0;
	int result=0;//result==0 indicate that x1,y1 is the wrong position
				 //result==1 indicate that they are legal position
	if(x1<0 || x1>=NUM || y1<0 || y1>=NUM)//棋子的位置在棋盘外面
		return 0;
	//横向--当前左
	x=x1;
	//y==0;
	yes=0;
  	//    kernel[NUM][NUM]    :     0 for none,1 for white,2 for black
	for(i=y1-1;i>=0;i--)
	{
		if(kernel[x][i]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[x][i]==temp)
			break;
		else
			yes=1;
	}
	if((i!=0-1) && (yes==1))
	{
		for(i++;i<y1;i++)
		{//    kernel[NUM][NUM]    :     0 for none,1 for white,2 for black
			kernel[x][i]=temp;//temp代表当前棋手的颜色,将棋子翻成自己的颜色!!
			result=1;
		}
	}
	//横向--当前向右
	//x==x1;
	//y==NUM;
	yes=0;
	for(i=y1+1;i<NUM;i++)
	{
		if(kernel[x][i]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[x][i]==temp)
			break;
		else
			yes=1;
	}
	if((i!=NUM) && (yes==1))
	{
		for(i--;i>y1;i--)
		{//    kernel[NUM][NUM]    :     0 for none,1 for white,2 for black
			kernel[x][i]=temp;
			result=1;
		}
	}
	//竖向--向上
	//x==0;
	y=y1;
	yes=0;
	for(i=x1-1;i>=0;i--)
	{
		if(kernel[i][y]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[i][y]==temp)
			break;
		else
			yes=1;
	}
	if((i!=0-1) && (yes==1))
	{
		for(i++;i<x1;i++)
		{//    kernel[NUM][NUM]    :     0 for none,1 for white,2 for black
			kernel[i][y]=temp;
			result=1;
		}
	}
	//竖向--向下
	//x==NUM;
	//y==y1;
	yes=0;
	for(i=x1+1;i<NUM;i++)
	{
		if(kernel[i][y]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[i][y]==temp)
			break;
		else
			yes=1;
	}
	if((i!=NUM) && (yes==1))
	{
		for(i--;i>x1;i--)
		{
			kernel[i][y]=temp;
			result=1;
		}
	}
	//斜向左上
	//x==0;
	//y==y1;
	yes=0;
	for(i=x1-1,j=y1-1;(i>=0)&&(j>=0);i--,j--)
	{
		if(kernel[i][j]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[i][j]==temp)
			break;
		else
			yes=1;
	}

	if((i!=0-1) && (j!=-1) && (yes==1))
	{
		for(i++,j++;i<x1;i++,j++)
		{
			kernel[i][j]=temp;
			result=1;
		}
	}
	//斜向上向右
	yes=0;

	for(i=x1-1,j=y1+1;(i>=0)&&(j<NUM);i--,j++)
	{
		if(kernel[i][j]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[i][j]==temp)
			break;
		else
			yes=1;
	}

	if((i!=0-1) && (j!=NUM) && (yes==1))
	{
		for(i++,j--;i<x1;i++,j--)
		{
			kernel[i][j]=temp;
			result=1;
		}
	}
	//斜向左下
	yes=0;

	for(i=x1+1,j=y1-1;(i<NUM)&&(j>=0);i++,j--)
	{
		if(kernel[i][j]==0)
		{
			yes=0;
			break;
		}
		else if(kernel[i][j]==temp)
			break;
		else
			yes=1;
	}

	if((i!=NUM) && (j!=-1) && (yes==1))
	{
		for(i--,j++;i>x1;i--,j++)
		{
			kernel[i][j]=temp;
			result=1;
		}
	}
	//斜向右下
	yes=0;

	for(i=x1+1,j=y1+1;(i<NUM)&&(j<NUM);i++,j++)
	{
		if(kernel[i][j]==0)
		{
			yes=0;//无改动
			break;
		}
		else if(kernel[i][j]==temp)
			break;
		else
			yes=1;//有改动
	}

	if((i!=NUM) && (j!=NUM) && (yes==1))
	{
		for(i--,j--;i>x1;i--,j--)
		{
			kernel[i][j]=temp;
			result=1;
		}
	}
	if(result==1)
		kernel[x1][y1]=temp;
	return result;//返回状态 1:OK,0:ERROR
}

int CBWChessDlg::IsEnd(/*int *x1, int *y1, */int whogo)
{//whogo 1:代表黑色,2代表白色
	int i,j;//行列坐标
	int x,y;
	int wn=0,bn=0; //wn:代表白色可放棋子的个数,bn:代表黑色可放棋子的个数(本函数的功能1)
	int btp_x=-7,btp_y=-7,wtp_x=-7,wtp_y=-7;
	int temp,temp2;

	if(!wsp.isempty())
		wsp.destroy();//先清空,再存储新的可下子的位置(本函数的功能2)

	if(!bsp.isempty())
		bsp.destroy();

	for(i=0;i<NUM;i++)
		for(j=0;j<NUM;j++)
		{
			if(kernel[i][j]==0)
			{
				//水平向左
				if(Check(i,j-1) && Check(i,j-2))//没有越界且此位置有棋子
				{
					x=i,y=j;
					temp=kernel[x][y-1];
					for(y-=2;y>=0;y--)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);//白色可放子的位置
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);//黑色可放子的位置
								}
							}
							break;
						}
					}
				}
				//水平向右
				if(Check(i,j+1) && Check(i,j+2))
				{
					x=i,y=j;
					temp=kernel[x][y+1];
					for(y+=2;y<NUM;y++)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}
				//垂直向上
				if(Check(i-1,j) && Check(i-2,j))
				{
					x=i,y=j;
					temp=kernel[x-1][y];
					for(x-=2;x>=0;x--)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}

				//垂直向下
				if(Check(i+1,j) && Check(i+2,j))
				{
					x=i,y=j;
					temp=kernel[x+1][y];
					for(x+=2;x<NUM;x++)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}

				//斜向左上
				if(Check(i-1,j-1) && Check(i-2,j-2))
				{
					x=i,y=j;
					temp=kernel[x-1][y-1];
					for(x-=2,y-=2;(x>=0) && (y>=0);x--,y--)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}

				//斜向右上
				if(Check(i-1,j+1) && Check(i-2,j+2))
				{
					x=i,y=j;
					temp=kernel[x-1][y+1];
					for(x-=2,y+=2;(x>=0) && (y<NUM);x--,y++)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}

				//斜向左下
				if(Check(i+1,j-1) && Check(i+2,j-2))
				{
					x=i,y=j;
					temp=kernel[x+1][y-1];
					for(x+=2,y-=2;(x<NUM) && (y>=0);x++,y--)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}

				//斜向右下
				if(Check(i+1,j+1) && Check(i+2,j+2))
				{
					x=i,y=j;
					temp=kernel[x+1][y+1];
					for(x+=2,y+=2;(x<NUM) && (y<NUM);x++,y++)
					{
						temp2=kernel[x][y];
						if(temp2==0)
							break;
						if(temp2!=temp)
						{
							if(temp2==1)
							{
								if(wtp_x!=i || wtp_y!=j)
								{
									wtp_x=i,wtp_y=j;
									wn++;
									wsp.push (i,j);
								}
							}
							else
							{
								if(btp_x!=i || btp_y!=j)
								{
									btp_x=i,btp_y=j;
									bn++;
									bsp.push (i,j);
								}
							}
							break;
						}
					}
				}

			}//end if
		}//end second for
	if((bn==0) && (wn==0))
		return -1;//return -1 for both
	if((bn>=2) && (wn>=2))
		return 2;///return 2 for have more than one
	switch(whogo)
	{
	//whogo 1:代表黑色,2代表白色
	case 1://代表黑色
		if(wn==0)
		return 0;//return 0 for the int have no position
		break;
		case 2://2代表白色
		if(bn==0)
		return 0;//return 0 for the int have no position
		break;
	}
	return 2;//return 2 for have more than one
}

int CBWChessDlg::Check(int x, int y)
{
	if(x<0 || x>=NUM || y<0 || y>=NUM)
		return 0;//越界为0
	if(kernel[x][y]==0)
		return 0;//无子为0
	return 1;

}

int CBWChessDlg::Walk1(int *x1, int *y1, int flag)//寻找最佳位置给(x1,x2)
{
	int fv=flag;//棋子颜色 2 黑 1 白
	int k,n;
		if(fv==1)//1:白色
			n=wsp.Len();
		else// 2:黑色
			n=bsp.Len();
       srand( (unsigned)time( NULL ) );
		k=rand()%n+1;		

	//算法开始!! 本算法采用随机法
	for(n=1;n<=k;n++)
	{
		if(fv==1)//1:白色
			wsp.pop(x1,y1);
		else// 2:黑色
			bsp.pop(x1,y1);
		//i,j是可以放棋子的坐标
	}	
	if(fv==1)//1:白色
		wsp. destroy();
		else// 2:黑色
		bsp. destroy();
	return 0;
}


void CBWChessDlg::Calcu_BW()//棋子计数
{
	int nw=0,nb=0;
	int i,j;
	for(i=0;i<NUM;i++)
		for(j=0;j<NUM;j++)
			if(kernel[i][j]==1)
				nw++;
			else if(kernel[i][j]==2)
				nb++;

	num_black=nb;
	num_white=nw;
}

int CBWChessDlg::IsInPanel(CPoint &pt)//判断是否在棋盘上
{
	if(pt.x<=m_wXNull || pt.x>=(m_wXNull + NUM*m_wStoneWidth))
		return 0;
	if(pt.y<=m_wYNull || pt.y>=(m_wYNull + NUM*m_wStoneHeight))
		return 0;
	return 1;
}

void CBWChessDlg::ShowNumber(int isTime)//刷新  时间和棋子的个数
{
	BCount.SetNumber(num_black);
	WCount.SetNumber(num_white);
	if(isTime)
	{
		TimeCount.SetNumber(m_PassedTime);
		TimeCount0.SetNumber(m_PassedTime0);
	}
}

void CBWChessDlg::OnTimer(UINT nIDEvent) //计时
{
	if(nIDEvent==PASSEDTIME)//尚未更新
	{
		if(!m_byColor)//白色
			m_PassedTime++;
		else//黑色
			m_PassedTime0++;
		ShowNumber(1);//“1”代表时间也要刷新
		if(g_nRunMode == MODE_2PLAYER && !g_nIsNoTimeLimit)//人对人,限时
		{
			if((m_PassedTime>=g_nTimeLimit) || (m_PassedTime0>=g_nTimeLimit))
			{//超时!!游戏结束
				m_bGameOver=TRUE;
				if(m_TimerOn)
				{
					KillTimer(PASSEDTIME);
					m_TimerOn=0;
				}
				m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);
				m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);
				m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);
				AddStringToList(0,0,0,(m_PassedTime>=g_nTimeLimit)? 1 : 2);
				PlaySounds(IDSOUND_USERWIN);
                //弹出游戏结束的对话框
				MsgBox((m_PassedTime>=g_nTimeLimit)? IDS_BLACK_LIMIT : IDS_WHITE_LIMIT ,IDS_TITLE_CHINESE);
			}
		}
	}
	CDialog::OnTimer(nIDEvent);
}

void CBWChessDlg::OnUndo() 
{
	if(g_nRunMode==MODE_NETWORK)//网络2
	{
		AfxMessageBox("你不能作弊!");
	    return;
	}
	
	
	m_PeekOnce=0;
	if(m_UndoPoint.IsEmpty())//已为空,m_UndoPoint的类名是 Cundo
	{
		PlaySounds(IDSOUND_ERROR);
		MsgBox(IDS_CANNOT_UNDO1_CHINESE, IDS_TITLE_CHINESE);//弹出无法悔棋的对话框
		return;
	}
	if (m_bGameOver)   
		return;

	int c1,c2,i,j,k=0;
	c1=m_UndoPoint.GetTopColor();//获取颜色
	int temp[NUM*NUM];
	m_UndoPoint.pop(temp);//获取棋盘
	RemoveStringFromList();
	if(g_nRunMode == MODE_WITH_COMPUTER)//人机对战
	{
		if(c1==m_byColor)
		{
			while(!m_UndoPoint.IsEmpty())
			{
				c2=m_UndoPoint.GetTopColor();
				RemoveStringFromList();
				if(c1!=c2)
				{
					m_UndoPoint.pop(temp);
					break;
				}
				else
				{
					int again_pop[NUM*NUM];
					m_UndoPoint.pop(again_pop);
				}
			}// end while
		}//end if
	}
	else
	{
		if(m_UndoPoint.IsEmpty())
		{
			if(g_bUserBlack)
				m_byColor=0;
			else
				m_byColor=1;
		}
		else
		{
			m_byColor=m_UndoPoint.GetTopColor ();
		}
	}
	for(i=0;i<NUM;i++)
		for(j=0;j<NUM;j++)
		{
			kernel[i][j]=temp[k];
			k++;
		}

	IsEnd(!m_byColor+1);
	if(!m_bGameOver && g_bPeepOften)
		OnCanplace();
	m_HintOnce=0;
	Calcu_BW();
	ShowNumber();
	PlaySounds(IDSOUND_UNDO);
	InvalidateRect(m_Client, TRUE);
	UpdateWindow();
}

void CBWChessDlg::duplicate()//保存当前棋盘和当前颜色,为悔棋作准备
{
	int temp[NUM*NUM];
	int i,j,k=0;
	for(i=0;i<NUM;i++)
		for(j=0;j<NUM;j++)
			temp[k++]=kernel[i][j];
	m_UndoPoint.push(temp,m_byColor);
}

void CBWChessDlg::Place(int *x, int *y,int color)
{//获取最佳位置
	int mx=0,my=0;
	Walk1(&mx,&my,color);
	*x=mx;
	*y=my;		
}

void CBWChessDlg::OnBest() //显示英雄榜
{
    CBestDlg bestDlg;
    bestDlg.DoModal();	
}

void CBWChessDlg::OnHint() // 响应“提示”
{
	const int HINTSIZE=7;
	if (m_bGameOver)  
		return;
	if(m_HintOnce)
		return;
	if(g_nRunMode == MODE_2PLAYER)//人对人
	{
		if(((m_HintTime0>=g_nCanHintTimeW) && m_byColor) ||
			((m_HintTime1>=g_nCanHintTimeB) && !m_byColor))
		{
			CString str1,str2;
			TCHAR s[200];
			str1.LoadString(IDS_MORETHANTHREE_CHINESE);//代表“我已提示了你%d次,不能再提示了!”
			str2.LoadString(IDS_TITLE_CHINESE);//代表“黑白棋”
			if(m_HintTime0>=g_nCanHintTimeW)
				wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeW);
			else
				wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeB);
			CString str(s);
			MsgBox(str,str2);//给出对话框
			return;// 退出提示
		}
		if(m_byColor)//次数累加
			m_HintTime0++;
		else
			m_HintTime1++;
	}
	else // 人对机
	{
		if(m_HintTime0>=g_nCanHintTimeW || m_HintTime1>=g_nCanHintTimeB)//0 白 1黑
		{
			CString str1,str2;
			TCHAR s[200];
			str1.LoadString(IDS_MORETHANTHREE_CHINESE);
			str2.LoadString(IDS_TITLE_CHINESE);
			if(m_HintTime0>=g_nCanHintTimeW)
				wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeW);
			else
				wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeB);
			CString str(s);
			MsgBox(str,str2);
			return;
		}
		else
		{
			if(m_byColor)
				m_HintTime0++;
			else
				m_HintTime1++;
		}
	}
	int px,py;
	Walk1(&py,&px,!m_byColor+1);//寻找最佳点
	x1 = px*m_wStoneWidth + m_wXNull-HINTSIZE + m_wStoneWidth / 2;
	y1 = py*m_wStoneHeight + m_wYNull-HINTSIZE + m_wStoneHeight / 2;
	x2 = px*m_wStoneWidth + m_wXNull+HINTSIZE + m_wStoneWidth / 2;
	y2 = py*m_wStoneHeight + m_wYNull+HINTSIZE + m_wStoneHeight / 2;
    //矩形:(x1,y1,x2,y2)
	CClientDC dc(this);//画 “X"
	COLORREF crColor = m_byColor ? RGB(255,255,255) : RGB(0,0,0);//1 画 白
	CPen pen(PS_SOLID, 2, crColor);
	CPen *pOldPen = dc.SelectObject(&pen);	
	dc.MoveTo(x1, y1);
	dc.LineTo(x2, y1);
	dc.LineTo(x2, y2);
	dc.LineTo(x1, y2);
	dc.LineTo(x1, y1);
	dc.LineTo(x2, y2);
	dc.MoveTo(x2, y1);
	dc.LineTo(x1, y2);
	dc.SelectObject(pOldPen);
	m_HintOnce=1;
}

void CBWChessDlg::MoveCursor(int x, int y)
{//从当前(m,n)位置向(x,y)走,x,y 是以像素为单位的,所使用的平面是窗口平面
	//每次移动鼠标之前,系统都会根据 m_byColor 的值载入光标,0载入黑手,1载入白手,之所以相反(0白1黑),
	//是因为系统载入光标时,用户还没有点击棋盘,m_byColor代表的前一个棋手的颜色。
	//但是本函数在调用时,m_byColor代表的是当前棋手的颜色
	//轮流到计算机下时,在计算机下棋之前,由于计算机不移动鼠标,也不敲击键盘,因此光标不会更新,
	//仍使用前一个棋手的光标,故在此处必须修正!!
	 m_byColor=!m_byColor;
     ::SetCursor(AfxGetApp()->LoadCursor(m_byColor ? IDC_WHITE_HAND:IDC_BLACK_HAND));//修正部分
      m_byColor=!m_byColor;
	if(!g_bMovePlace)
	{
		return;
	}
	CPoint pt;
	GetCursorPos(&pt);
	int m,n;
	int sleep_interval=2;
	m=pt.x ;
	n=pt.y ;
	if(m >x)
	{
		while(m>x)//向左走
		{
			m-=g_nMoveSpeeds;
			Sleep(sleep_interval);
			SetCursorPos(m,n);
		}
	}
	else if(m<x)//向右走
	{
		while(m<x)
		{
			m+=g_nMoveSpeeds;
			Sleep(sleep_interval);
			SetCursorPos(m,n);
		}
	}

	if(n >y)
	{
		while(n>y)//向上走
		{
			n-=g_nMoveSpeeds;
			Sleep(sleep_interval);
			SetCursorPos(m,n);
		}
	}
	else if(n < y)//向下走
	{
		while(n < y)
		{
			n+=g_nMoveSpeeds;
			Sleep(sleep_interval);
			SetCursorPos(m,n);
		}
	}
}

void CBWChessDlg::OnCanplace() //本函数计算当前棋手可下的位置,并标志出来!(X)
{
	if (m_bGameOver)     
		return;
	if(m_PeekOnce)
		return;
	int px,py;
	int xx1,yy1;
	int length,hy;
	//CClientDC dc(this);;
	CDC *dc=GetDC();
	if(m_byColor)//判断是否有位置可填
		length=wsp.isempty();
	else
		length=bsp.isempty();
	if(length)//无,结束
		return;
	do
	{
		if(m_byColor)
			length=wsp.GetNextPos(&py,&px,&hy);
		else
			length=bsp.GetNextPos(&py,&px,&hy);
		xx1 = px*m_wStoneWidth + m_wXNull;//-4 + m_cxGrid / 2;
		yy1 = py*m_wStoneHeight + m_wYNull;//-4 + m_cyGrid / 2;
		if(m_byColor)
			DrawBitmap(dc,xx1,yy1,IDB_CANPLACE2, SRCCOPY);
		else
			DrawBitmap(dc,xx1,yy1,IDB_CANPLACE1, SRCCOPY);

	}while(length);
	if(m_byColor)
		wsp.CopyBackIndex();
	else
		bsp.CopyBackIndex();
	m_PeekOnce=1;
	ReleaseDC(dc);
}

void CBWChessDlg::OnSetting() //响应“设置”命令
{
	CSettingDlg dlg;
	dlg.DoModal ();//显示“设置”对话框
	if(g_bTopMost)
		SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
	else
		SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
}

void CBWChessDlg::OnOpen() //响应“OPEN”命令
{
	if(!m_bGameOver && g_bPrompt)
		if(MsgBox(IDS_ABORT,IDS_TITLE_CHINESE,2)==IDCANCEL)
			return ;

	TCHAR sFilter[50]="BWChess File (*.BWS)|*.BWS||";
	CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
					sFilter);
	int result=dlg.DoModal();
	if(result==IDOK)
	{
		CFile file(dlg.GetPathName(), CFile::modeRead);
		int buffer[9000],len,t;
		unsigned int reallen=file.Read(buffer,9000*sizeof(int));
		if((reallen!=(buffer[0]*sizeof(int))) || (reallen<140))
		{
			MsgBox(IDS_OPENERROR1,IDS_TITLE_CHINESE);
			return;
		}
		if(buffer[1]!=EDITION)
		{
			MsgBox(IDS_OPENERROR2,IDS_TITLE_CHINESE);
			return;
		}
		if(buffer[2])
		{
			MsgBox(IDS_OPENERROR3,IDS_TITLE_CHINESE);
			return;
		}
        int i,j;
		len=buffer[0]/2-1;
		BOOL changeI=FALSE;
		for(t=0;t<len;t++)
		{
			if(buffer[t+3]!=buffer[3+len+t])
			{
				changeI=TRUE;
				break;
			}
		}
		if(changeI)
		{
			MsgBox(IDS_OPENERROR1,IDS_TITLE_CHINESE);
			return;
		}

		if(m_TimerOn)
		{
			KillTimer(PASSEDTIME);
			m_TimerOn=0;
		}
		m_bGameOver = FALSE;	              
		m_Skip=0;
		i=0;
		g_nStoneNum=0;
		m_HintOnce=0;//0 for have not hinted yet,1 for have hinted
		m_PeekOnce=g_bPeepOften;
		m_IsGameStart=0;
		ListInfo.destroy();
		m_ListInfo.ResetContent();
		if(!m_UndoPoint.IsEmpty())
			m_UndoPoint.Destroy();
		len=3;///important
		m_byColor=buffer[len++];
		g_nRunMode=buffer[len++];
		m_PassedTime=buffer[len++];
		m_PassedTime0=buffer[len++];
		g_nSkill=buffer[len++];
		g_bUserBlack=buffer[len++];
		m_HintTime0=buffer[len++];
		m_HintTime1=buffer[len++];
		g_nTimeLimit=buffer[len++];
		g_nIsNoTimeLimit=buffer[len++];
		len+=5;		
		for(i=0;i<NUM;i++)
			for(j=0;j<NUM;j++)
				kernel[i][j]=buffer[len++];
		int x,y,num,tc;
		num=buffer[len++];
		while(num>0)
		{
			x=buffer[len++];
			y=buffer[len++];
			tc=buffer[len++];
			AddStringToList(x,y,tc);
			num--;
		}
		//read m_UndoPoint
		num=buffer[len++];
		while(num>0)
		{
			int temp[NUM*NUM];
			for(x=0;x<NUM*NUM;x++)
				temp[x]=buffer[len++];
			tc=buffer[len++];
			m_UndoPoint.push(temp,tc);
			num--;
		}
		IsEnd(1);
		Calcu_BW();
		SetChessTitle();
		m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_HINT,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_UNDO,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED);
		InvalidateRect(NULL,TRUE);
		SetTimer(PASSEDTIME,1000,NULL);
		m_TimerOn=1;
	}	
}

void CBWChessDlg::OnSave() //响应“SAVE”命令
{
	TCHAR sFilter[50]=_T("BWChess File (*.BWS)|*.BWS||");
	TCHAR sExt[10]=_T("BWS");
	CFileDialog dlg(FALSE,sExt,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
					sFilter);
	if(dlg.DoModal()==IDOK)
	{
		CFile file(dlg.GetPathName(),CFile::modeCreate | CFile::modeWrite);
		int buffer[9000],len=3;// the buffer need about 4000 size
		for(int ii=0;ii<2;ii++)//copy twice
		{
			buffer[len++]=m_byColor;
			buffer[len++]=g_nRunMode;
			buffer[len++]=m_PassedTime;
			buffer[len++]=m_PassedTime0;
			buffer[len++]=g_nSkill;
			buffer[len++]=g_bUserBlack;
			buffer[len++]=m_HintTime0;
			buffer[len++]=m_HintTime1;
			buffer[len++]=g_nTimeLimit;
			buffer[len++]=g_nIsNoTimeLimit;
			//restore 5 position for future use
			buffer[len++]=0;
			buffer[len++]=0;
			buffer[len++]=0;
			buffer[len++]=0;
			buffer[len++]=0;
			int i,j;
			for(i=0;i<NUM;i++)
				for(j=0;j<NUM;j++)
					buffer[len++]=kernel[i][j];
			int num=ListInfo.Len();
			buffer[len++]=num;
			int x,y,tc;
			int re;
			stack ts;
			do
			{
				re=ListInfo.GetNextPos(&x,&y,&tc);
				ts.push(x,y);
				ts.SetMarks (tc);
			}
			while(re);
			do
			{
				re=ts.GetNextPos(&x,&y,&tc);
				buffer[len++]=x;
				buffer[len++]=y;
				buffer[len++]=tc;
			}
			while(re);
			ListInfo.CopyBackIndex();
			// store m_UndoPoint
			int tlen=m_UndoPoint.Len();
			buffer[len++]=tlen;
			int tempUndo[NUM*NUM];
			do
			{
				re=m_UndoPoint.GetNextPos(tempUndo,&tc);
				for(x=0;x<NUM*NUM;x++)
					buffer[len++]=tempUndo[x];
				buffer[len++]=tc;
			}
			while(re);
			m_UndoPoint.CopyBackIndex();
		}
		buffer[0]=len;
		buffer[1]=EDITION;//this the edition of the banben
		buffer[2]=(int)m_bGameOver;
		file.Write(buffer,len*sizeof(int));
	}	
}

void CBWChessDlg::AddStringToList(int x, int y, int color,int win)//加入信息于列表框
{
	CString str;
	int result=m_ListInfo.GetCount();
	if(!win)
	{
		if(color)
			str.LoadString(IDS_SBLACK);// “%2d.黑棋: %c %d”
		else
			str.LoadString(IDS_SWHITE);
		TCHAR s[100];
		wsprintf(s, str.GetBuffer(256),result+1, y+65,x+1);
		m_ListInfo.AddString(s);
		ListInfo.push(x,y);
		ListInfo.SetMarks(color);
	}
	else
	{
		if(win==1)//白 win
			str.LoadString(IDS_WHITEWIN_CHINESE);
		else if(win==2)//黑 win
			str.LoadString(IDS_BLACKWIN_CHINESE);
		else//本局平局
			str.LoadString(IDS_TIE);
		m_ListInfo.AddString(str);
	}
	m_ListInfo.SetCurSel(result);//将当前新加入的显色(兰色)
	m_ListInfo.SetFocus();
}

void CBWChessDlg::RemoveStringFromList()//于列表框删除信息
{
	int index=m_ListInfo.GetCount();
	m_ListInfo.DeleteString(index-1);
	int x,y;
	ListInfo.pop(&x,&y);
	ListInfo.GetTop(x,y);
	m_CurPt.x =x,m_CurPt.y=y;
	index=m_ListInfo.GetCount();
	if(index)
	{
		m_ListInfo.SetCurSel(index-1);
		m_ListInfo.SetFocus();
	}
}

void CBWChessDlg::OnSaveinfo() //响应“导出走棋信息”
{
	TCHAR sFilter[50]=_T("文本文件(*.TXT)|*.TXT||");
	TCHAR sExt[10]=_T("txt");
	CFileDialog dlg(FALSE,sExt,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
					sFilter);
	if(dlg.DoModal()==IDOK)
	{
		CFile file(dlg.GetPathName(),CFile::modeCreate | CFile::modeWrite | CFile::typeText);
		TCHAR buffer[300];
		int len=0,index=0;
		len=GetWindowText(buffer,300);
		buffer[len++]=13;
		buffer[len++]=10;
		file.Write(buffer,len);
		len=m_ListInfo.GetCount();
		while(index<len)
		{
			int slen=m_ListInfo.GetText(index++,buffer);
			buffer[slen]=13;
			buffer[slen+1]=10;
			file.Write(buffer,slen+2);
		}
	}	
}

BOOL CBWChessDlg::PreTranslateMessage(MSG* pMsg) //检测加速键消息是否被处理了
{//The TranslateAccelerator function processes accelerator keys for menu commands
    if(!::TranslateAccelerator(m_hWnd,hAccelerator,	pMsg))
		return CDialog::PreTranslateMessage(pMsg);
	return TRUE;
}


void CBWChessDlg::SetChessTitle()//载入标题
{
	CString str;
	if (g_nRunMode==MODE_WITH_COMPUTER && g_bUserBlack)
		str.LoadString(IDS_SINGLE_USER_CHINESE);//“黑白棋: 与计算机对弈, 你执黑先下”
	else if (g_nRunMode==MODE_WITH_COMPUTER && !g_bUserBlack)
		str.LoadString(IDS_SINGLE_COMPUTER_CHINESE);//“黑白棋: 与计算机对弈, 计算机执黑先下”
	else if	(g_nRunMode==MODE_2PLAYER)
	{
		if(g_nIsNoTimeLimit)
			str.LoadString(IDS_DOUBLE_NOLIMIT_CHINESE);//“黑白棋: 双人同机对弈,不限时”
		else
		{
			str.LoadString(IDS_DOUBLE_LIMIT_CHINESE);//“黑白棋: 双人同机对弈,限时%d秒”
			TCHAR str1[200];
			wsprintf(str1, str.GetBuffer(256), g_nTimeLimit);
			str=str1;
		}
	}
	SetWindowText(str);//显示标题
}

void CBWChessDlg::OnListDoubleClicked()//双击列表,撤消操作
{
	if(m_bGameOver || g_nIsDemo)//游戏已结束或正在演示
		return;
	int nSel=m_ListInfo.GetCurSel();
	int length=m_ListInfo.GetCount()-1;
		while(length>=nSel)//依次进行撤消
		{
			OnUndo();
			length=m_ListInfo.GetCount()-1;
		}
}

void CBWChessDlg::DrawFrame(CDC *dc)//画棋盘
{
	const int Sx=1;
	const int Sy=1;
	int i,j;
	int wx0,wy0,wx1,wy1;
	wx0=Sx,wy0=Sy;
	DrawBitmap(dc,wx0,wy0,IDB_F1_1,SRCCOPY);
	wx0=Sx+m_wFrameHeight+NUM*m_wFrameWidth,wy0=Sy;
	DrawBitmap(dc,wx0,wy0,IDB_F1_10,SRCCOPY);
	wx0=Sx,wy0=Sy+m_wFrameHeight+NUM*m_wStoneHeight;
	DrawBitmap(dc,wx0,wy0,IDB_F10_1,SRCCOPY);
	wx0=Sx+m_wFrameHeight+NUM*m_wStoneWidth,wy0=Sy+m_wFrameHeight+NUM*m_wStoneHeight;
    DrawBitmap(dc,wx0,wy0,IDB_F10_10,SRCCOPY);
    wx0=Sx+m_wFrameHeight,wy0=Sy,wx1=Sx+m_wFrameHeight,wy1=Sy+m_wFrameHeight+m_wStoneWidth*NUM;
	for(i=1,wx0=Sx+m_wFrameHeight,wy0=Sy,wx1=Sx+m_wFrameHeight,wy1=Sy+m_wFrameHeight+m_wStoneWidth*NUM;i<NUM+1;i++)
	{//画水平的边框8格
        DrawBitmap(dc,wx0,wy0,IDB_F1_2+i-1,SRCCOPY);
		DrawBitmap(dc,wx1,wy1,IDB_F10_2+i-1,SRCCOPY);		
		wx0+=m_wFrameWidth;
		wx1+=m_wFrameWidth;
	}
	for(i=0,wx0=Sx,wy0=Sy+m_wFrameHeight,wx1=Sx+m_wFrameHeight+NUM*m_wStoneWidth,wy1=Sy+m_wFrameHeight;i<NUM;i++)
	{//画垂直的边框8格	
        DrawBitmap(dc,wx0,wy0,IDB_F2_1+i,SRCCOPY);
		DrawBitmap(dc,wx1,wy1,IDB_F2_10+i,SRCCOPY);
		wy0+=m_wStoneHeight;
		wy1+=m_wStoneHeight;
	}
	for(i=0,wx0=Sx+m_wFrameHeight,wy0=Sy+m_wFrameHeight;i<NUM;i++,wx0=Sx+m_wFrameHeight,wy0=i*m_wStoneHeight+Sy+m_wFrameHeight)
		for(j=0;j<NUM;j++,wx0+=m_wStoneWidth)
		{//画棋盘8*8
			if(!kernel[i][j])
			{
				CPoint pt(wx0,wy0);
				DrawBitmap(dc,wx0,wy0,IDB_EMPTY,SRCCOPY);
			}
		}		
}

void CBWChessDlg::OnDemo() //响应“计算机演示/终止计算机对弈”命令
{
	CString str;
	if(g_nIsDemo)//响应“终止计算机对弈”命令
	{
		::TerminateThread(m_CcThread->m_hThread,0);
		m_pMenu->EnableMenuItem(IDM_NEW,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_OPEN,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_REPLAY,MF_ENABLED);
		str.LoadString(IDS_DEMOTITLE0);//“计算机演示[&M]...\tCtrl+M”
		m_pMenu->ModifyMenu(IDM_DEMO,MF_BYCOMMAND | MF_STRING,IDM_DEMO,str);
        //程序已经在“演示”,菜单已被改为“终止计算机对弈”,因此现在要恢复为“计算机演示”
		g_nIsDemo=0;
		m_bGameOver=TRUE;
	}
	else//响应“计算机演示”命令
	{
		int HaveKilled=0;
		if(m_TimerOn)//终止计时
		{
			HaveKilled=1;
			KillTimer(PASSEDTIME);
			m_TimerOn=0;
		}

		if(!m_bGameOver && g_bPrompt)//游戏没有结束
		{
			if(MsgBox(IDS_ABORT,IDS_TITLE_CHINESE,2)==IDCANCEL)
			{//弹出对话框询问
				if(HaveKilled)//取消对话框,恢复计时
				{					
					SetTimer(PASSEDTIME,1000,NULL);
					m_TimerOn=1;
				}
				return;
			}
		}
       //OK对话框
		CDemo dlg;//弹出计算机对弈对话框
		if(dlg.DoModal()==IDCANCEL)
		{
			if(HaveKilled)
			{				
				SetTimer(PASSEDTIME,1000,NULL);
				m_TimerOn=1;
			}
			return;
		}
		//修改菜单
		m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_NEW,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_OPEN,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED);
		str.LoadString(IDS_DEMOTITLE1);
		m_pMenu->ModifyMenu(IDM_DEMO,MF_BYCOMMAND | MF_STRING,IDM_DEMO,str);
        //修改菜单为“终止计算机对弈”
		int flag=0;//标志是否为历史棋局
		if(dlg.m_IsFile)//演示历史棋局
		{
			CFile file(dlg.m_FilePath, CFile::modeRead);
			int buffer[9000],len;
			file.Read(buffer,9000*sizeof(int));
			len=18+NUM*NUM;///important
			m_PointGo.destroy();
			int x,y,num,tc;
			stack tt;
			num=buffer[len++];//num代表走棋的步数
			while(num>0)//进栈
			{
				x=buffer[len++];
				y=buffer[len++];
				tc=buffer[len++];
				tt.push(x,y);
				tt.SetMarks(tc);
				num--;
			}
			while(!tt.isempty ())//再出栈入栈,顺序演示
			{
				tc=tt.GetMarks (0);
				tt.pop (&x,&y);
				m_PointGo.push(x,y);
				m_PointGo.SetMarks(tc);
			}
			flag=0;
		}
		else//不是历史棋局
		{
			CString str1;
			switch(g_nCbSkill)//黑方级别
			{
			case 1://黑方:初级
				switch(g_nCwSkill)//白方级别
				{
				case 1://白方:初级
					str1.LoadString(IDS_DEMO_TITLE_11);
					//“黑白棋:计算机演示->黑方:初级;白方:初级”
					break;
				case 2://白方:中级
					str1.LoadString(IDS_DEMO_TITLE_12);
					//黑白棋:计算机演示->黑方:初级;白方:中级
					break;
				case 3://白方:专家级
					str1.LoadString(IDS_DEMO_TITLE_13);
					//黑白棋:计算机演示->黑方:初级;白方:专家级
					break;
				}
				break;
			case 2://黑方:中级
				switch(g_nCwSkill)
				{
				case 1:
					str1.LoadString(IDS_DEMO_TITLE_21);
					//黑白棋:计算机演示->黑方:中级;白方:初级
					break;
				case 2:
					str1.LoadString(IDS_DEMO_TITLE_22);
					break;
				case 3:
					str1.LoadString(IDS_DEMO_TITLE_23);
					break;
				}
				break;
			case 3://黑方:高级
				switch(g_nCwSkill)
				{
				case 1:
					str1.LoadString(IDS_DEMO_TITLE_31);
					break;
				case 2:
					str1.LoadString(IDS_DEMO_TITLE_32);
					break;
				case 3:
					str1.LoadString(IDS_DEMO_TITLE_33);
					break;
				}
				break;
			}
			SetWindowText(str1);//设置标题,显示设置的信息
			flag=1;
		}
		g_nIsDemo=1;
		m_DemoOrReplay=1;
		m_CcThread=AfxBeginThread(CCplayFunc,(LPVOID )flag,THREAD_PRIORITY_NORMAL,
									0,CREATE_SUSPENDED);
		//创建一线程,对应的函数是 CCplayFunc(LPVOID p),优先级别NORMAL,阻塞状态
		m_Mutex.Lock();//互斥,不再响应棋盘上的点击事件
		m_CcThread->ResumeThread();	//执行线程
	}
	m_nIsContinueReplay=1;
}

UINT CCplayFunc(LPVOID p)//CCplayFunc(LPVOID p) 是CBWChessDlg类的友员函数
{
	CBWChessDlg *dlg=(CBWChessDlg *)(AfxGetApp()->m_pMainWnd); 
	//m_pMainWnd 指向主界面
	dlg->ComputerPlay ((int)p);//在子线程中执行计算机演示操作,主线程仍可响应用户输入
	return 0;
}

void CBWChessDlg::ComputerPlay(int flag)//计算机演示对弈
{
	InitParams();
	IsEnd(m_byColor+1);
	m_PeekOnce=(int)g_bPeepOften;
	Mutex1.Lock();
	g_nMutex=1;//确保此操作能一次性完成
	Mutex1.Unlock();
	InvalidateRect(&m_Client, FALSE);
	m_Mutex.Lock();//锁定棋盘
	while(1)
	{
		m_byColor = !m_byColor;	//棋手交换		// 1-Black  0-White
		int ptBest_x=0,ptBest_y=0,result=0,ret=0;
		if(flag)//无历史型的演示(级别无效)
		{
			if(m_byColor)
				Place(&ptBest_x,&ptBest_y,m_byColor+1);
			else
				Place(&ptBest_x,&ptBest_y,m_byColor+1);
		}
		else//有历史型的演示
		{///add here从栈里获得数据
			ret=m_PointGo.GetNextPos(&ptBest_x,&ptBest_y,&m_byColor);
		}
		BtoW(ptBest_x,ptBest_y,m_byColor+1);
		Calcu_BW();// 计算黑白棋子的数目
		result=IsEnd(!m_byColor+1);
		Mutex1.Lock();
		g_nMutex=1;
		Mutex1.Unlock();
		InvalidateRect(&m_Client, FALSE);
		UpdateWindow();
		m_Mutex.Lock();
		AddStringToList(ptBest_x,ptBest_y,m_byColor);
		PlaySounds(IDSOUND_PUTSTONE);
		if(!ret && !flag)
		{
			m_bGameOver=TRUE;
			break;
		}
		if(result==-1)//演示结束
		{
			CString str1,str2,str3,strPrompt;
			TCHAR str[300];
			int addp=0;
			m_bGameOver=TRUE;
			Calcu_BW();
			str2.LoadString (IDS_TITLE_CHINESE);//“黑白棋”
			if(num_white<num_black)
			{//本局黑棋胜。
				addp=2;
				str1.LoadString(IDS_BLACKWIN_CHINESE);
			}
			else if(num_white>num_black)
			{//本局白棋胜。
				addp=1;
				str1.LoadString(IDS_WHITEWIN_CHINESE);
			}
			else
			{//“本局平手。\n我们的水平不分上下!”
				addp=3;
				str1.LoadString(IDS_TIE_CHINESE);
			}
			str3.LoadString(IDS_END_CHINESE);
			//“黑棋%d子,白棋%d子”
			wsprintf(str, str3.GetBuffer(256), num_black,num_white);
			strPrompt = str;
			strPrompt += str1; 
			AddStringToList(0,0,0,addp);
			Mutex1.Lock();
			g_nMutex=1;
			Mutex1.Unlock();
			InvalidateRect(&m_Client,FALSE);
			m_Mutex.Lock();
			PlaySounds(IDSOUND_USERWIN);
			MsgBox(strPrompt,str2);//弹出显示演示结果的对话框
			break;
		}
		else if(result==0)//当前一方不能下,换下一方
			m_byColor=!m_byColor;//轮流
		Sleep(500*g_nCSpeed);//减慢演示速度
	}//end while
	CString strT;
	m_pMenu->EnableMenuItem(IDM_NEW,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_OPEN,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED);
	m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_ENABLED);
	if(m_DemoOrReplay)
	{
		strT.LoadString(IDS_DEMOTITLE0);//修改为“计算机演示[&M]...\tCtrl+M”
		m_pMenu->ModifyMenu(IDM_DEMO,MF_BYCOMMAND | MF_STRING,IDM_DEMO,strT);
		m_pMenu->EnableMenuItem(IDM_REPLAY,MF_ENABLED);//使“重温棋局”有效
	}
	else
	{//add here
		strT.LoadString(IDS_REPLAY0);//“重温棋局[&W]\tCtrl+W”
		m_pMenu->ModifyMenu(IDM_REPLAY,MF_BYCOMMAND | MF_STRING,IDM_REPLAY,strT);//"重温棋局"
		m_pMenu->EnableMenuItem(IDM_DEMO,MF_ENABLED);
	}
	g_nIsDemo=0;
	m_PointGo.CopyBackIndex();
}

void CBWChessDlg::OnReplay() //响应“重温棋局”
{
	CString str;
	if(g_nIsDemo)//正在演示
	{
		::TerminateThread(m_CcThread->m_hThread,0);//终止演示线程
		m_pMenu->EnableMenuItem(IDM_NEW,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_OPEN,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_ENABLED);
		m_pMenu->EnableMenuItem(IDM_DEMO,MF_ENABLED);

		str.LoadString(IDS_REPLAY0);//“重温棋局[&W]\tCtrl+W”
		m_pMenu->ModifyMenu(IDM_REPLAY,MF_BYCOMMAND | MF_STRING,IDM_REPLAY,str);

		g_nIsDemo=0;
		m_bGameOver=TRUE;
		m_PointGo.CopyBackIndex();
	}
	else//没有演示
	{
		int HaveKilled=0;
		if(m_TimerOn)
		{
			HaveKilled=1;
			KillTimer(PASSEDTIME);
			m_TimerOn=0;
		}
		if(!m_bGameOver && g_bPrompt)//游戏没有结束
		{
			if(MsgBox(IDS_ABORT,IDS_TITLE_CHINESE,2)==IDCANCEL)
				//“你确定要终止当前的对局吗?”“黑白棋”
			{//继续
				if(HaveKilled)
				{					
					SetTimer(PASSEDTIME,1000,NULL);
					m_TimerOn=1;
				}
				return;
			}
		}
		m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_NEW,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_OPEN,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_GRAYED);
		m_pMenu->EnableMenuItem(IDM_DEMO,MF_GRAYED);
		str.LoadString(IDS_REPLAY1);//载入“终止重温棋局[&W]\tCtrl+W”
		m_pMenu->ModifyMenu(IDM_REPLAY,MF_BYCOMMAND | MF_STRING,IDM_REPLAY,str);
		//duplicate stack
		if(m_nIsContinueReplay)
		{
			m_PointGo.destroy();
			while(!ListInfo.isempty())//将序列倒置,存入m_PointGo 栈中!!
			{
				int x,y,mark;
				mark=ListInfo.GetMarks(0);
				ListInfo.pop(&x,&y);
				m_PointGo.push(x,y);
				m_PointGo.SetMarks(mark);
			}
			m_nIsContinueReplay=0;//防止第二次赋值
		}
		g_nIsDemo=1;//开始演示标志
		m_DemoOrReplay=0;
		m_CcThread=AfxBeginThread(CCplayFunc,(LPVOID)0,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
		//派生演示线程,设置为历史棋盘“演示模式”,由“(LPVOID)0”表示
		m_Mutex.Lock();//互斥地演示
		m_CcThread->ResumeThread();	//开始演示!
	}
}

void AcceptCallback (DWORD ptr)//接受连接的处理函数
{

	CNetworking*	net = reinterpret_cast <CNetworking*> (ptr);

	if (Connection && Connection->IsConnected ())//清除多余的连接,但保留当前的连接
	{
		CConnection* c = net->GetAccepted ();
		while (c)
		{
			char nocon[] = "The host can not accept your connection at this time.";
			c->Send (nocon, sizeof (nocon));
			c->Disconnect ();
			delete c;
			c = net->GetAccepted ();
		}
	}

	else//没有连接,接受连接
	{
		if (Connection)
			delete Connection;

		Connection = net->GetAccepted ();//接受连接对象

		Connection->SetReceiveFunc (ReceiveCallback);//设置数据到达时的回调函数
		Connection->SetCloseFunc (CloseCallback);//设置连接关闭时要调用的回调函数

		AfxMessageBox("有人加入,连接成功,你先下");
		Sever=1;//设置为服务器模式
	}

}

UINT ReceiveFunc(int kk)//数据到达时的处理函数,是友员函数!!!!!!
{	
	CBWChessDlg *dlg=(CBWChessDlg *)(AfxGetApp()->m_pMainWnd);  
	if(kk!=10)//所有数据大于等于10,大于10是其他消息,等于10 是走棋消息,只用到前面3个字节,其他7个备用
	{
      szBuff[10]='\0';
      szBuff[0]='#';
      AfxMessageBox("不是所要的数据");
      char str[1000];				
      wsprintf(str,"%s",szBuff);
      AfxMessageBox(str);
	  return 0;
	}	


	if((szBuff[0]-48)==CMD_RESIGN)
	{
		AfxMessageBox("对手退出了");
		m_bGameOver=TRUE;
		return 0;
	}
	
	if((szBuff[0]-48)==CMD_OVER)
	{
		pppp=100;
	}

	if((szBuff[0]-48)==CMD_SKIP)
	{
		dlg->m_Skip=1;
	}
 
	 if(m_bGameOver)
	   return 1;

 
    int x=szBuff[1]-48;
	int y=szBuff[2]-48;

	if(m_bGameOver==false)
	dlg->Newchess(x,y);
	//销毁数据
	dlg=NULL;
	return 1;
}


void ReceiveCallback (DWORD ptr)//数据到达时的处理
{
	CConnection* c = reinterpret_cast <CConnection*> (ptr);

	int kk=c->Receive (szBuff, 1000);//接受数据

	ReceiveFunc(kk);//相关的数据处理函数
}


void CloseCallback (DWORD ptr)//关闭连接
{
	AfxMessageBox ("The connection was closed.");
    if (Connection)
	delete Connection;//关闭连接
    Connection=NULL;
	if(Sever==1)//为服务器
	{
		Networking.StopListen ();
        Networking.Listen(10205);
	}
	if(g_nRunMode==MODE_NETWORK)//网络模式
	m_bGameOver=true;//游戏结束
    Sever=2;//非网络模式
	ptr=ptr+0;
}

UINT ConnectFunc(LPVOID flag)//与主机进行连接的线程函数
{
	
    Cip m_ip;//创建IP对话框
	if (m_ip.DoModal()==IDCANCEL)//取消了	
	return (UINT)flag;
    BYTE IP1=m_ip.IP1;
    BYTE IP2=m_ip.IP2;
    BYTE IP3=m_ip.IP3;
    BYTE IP4=m_ip.IP4;
    char IP[16];
	wsprintf(IP,"%d.%d.%d.%d",IP1,IP2,IP3,IP4);
	AfxMessageBox(IP);
	int i=0;
	while(i<10&&Connection->Connect (IP, 10205)!=true)
	{   i++;
		Sleep(100);
	}
	if(i<10)
	{
		AfxMessageBox("连接成功,对手先下");
        Sever=0;//只有在连接之后才能设置客户机模式
	}

	else
    {
		AfxMessageBox("连接失败");
        Sever=2;
	}
	return (UINT)flag;
}

void  CBWChessDlg::OnConnect()//建立客户机
{
	if(Sever==1||Sever==0)
	{
         AfxMessageBox("已经建立了连接,请先断开连接");
		  return;
	}
	Sever=2;//设为非连网模式
	Connection = new CConnection ();//建立连接对象

	AfxBeginThread(ConnectFunc,0,THREAD_PRIORITY_NORMAL,0,NULL);//连接到服务器

    Connection->SetReceiveFunc(ReceiveCallback);//建立连接对象,设置数据到达时的回调函数
	   
    Connection->SetCloseFunc (CloseCallback);//设置连接被关闭时的回调函数

			
}

void  CBWChessDlg::OnHost()//建立服务器
{
	 if(Sever==1)
	 {
		  AfxMessageBox("已经建立了,不能重复建立");
		  return;
	 }
     
	 if(Sever==0)
	 {
	      AfxMessageBox("已经建立了连接,请先断开连接");
		  return;
	 }

      Sever=2;//设为非连网模式  
	if(Networking.Listen(10205))
		{
        AfxMessageBox("监听成功");
		Networking.SetAcceptFunc (AcceptCallback);//设置接受连接时的回调函数
		}
		else
        AfxMessageBox("监听失败");
}

void  CBWChessDlg::OnUnlink()
{
	if(	Connection->IsConnected ())
	Connection->Disconnect ();
	if(Sever==1)//为服务器
	Networking.StopListen ();
	Sever=2;//设为断开状态
}
int CBWChessDlg::Senddata(int x, int y, int command)//发送数据
{
	char  sz[11];
    	
    sz[0]=(char)(command+48);
	sz[1]=(char)(x+48);
	sz[2]=(char)(y+48);
	sz[3]='B';
    sz[4]='W';
	sz[5]='C';
	sz[6]='H';
	sz[7]='E';
	sz[8]='S';
	sz[9]='S';
	sz[10]='\0';

	if(Connection->Send(sz, strlen (sz))==SOCKET_ERROR )
	{
	 AfxMessageBox("数据发送失败");	
	 return 0;
	}
	return 1;
}


void CBWChessDlg::Newchess(int ptBest_x,int ptBest_y)//当对方数据到达时,更新窗口
{
        	        m_Mutex.Lock();
					m_byColor = !m_byColor;			// 1-Black  0-White,切换对手
					duplicate();//保存副本
					m_HintOnce=0;
					m_PeekOnce=0;
					BtoW(ptBest_y,ptBest_x,m_byColor+1);//将棋盘上被夹住的子变色
					CPoint pt;
					pt.x = ptBest_x*m_wStoneWidth + m_wXNull+m_wStoneWidth/2;
					pt.y = ptBest_y*m_wStoneHeight + m_wYNull+m_wStoneWidth/2;
					m_CurPt.x=ptBest_x;
					m_CurPt.y=ptBest_y;
					ClientToScreen(&pt);
					MoveCursor(pt.x, pt.y);//移动光标,此时m_byColor代表的是当前棋手的颜色
					AddStringToList(ptBest_y,ptBest_x,m_byColor);//将信息加入列表框
					InvalidateRect(m_Client, FALSE);
					UpdateWindow();//更新棋盘
					PlaySounds(IDSOUND_PUTSTONE);
                    if(m_Skip!=1&&pppp!=100)
					Ring(IsEnd(!m_byColor+1));//作善后处理,包括“游戏结束或对手无子可走”
		                  else
						  {
						     int kk=IsEnd(!m_byColor+1);
                             if(kk==0)
                             m_Skip=1;
						     else
						     m_Skip=0;
 
					         Calcu_BW();
	                   
						     ShowNumber(); 
	 	             if(pppp==100)
					 { 	  	 
					        int win=0;
						    int	addp=0;
						    m_bGameOver = TRUE;
			                if(m_TimerOn)
							{
				               KillTimer(PASSEDTIME);
			                   m_TimerOn=0;
							}
						CString str1,str2, str3,strPrompt;
			            TCHAR str[128];
			    	    g_nStoneNum=abs(num_black-num_white);
			     	    g_nBestMark=abs((num_white+num_black)*(num_white-num_black));
				        if(!(num_black && num_white))
				     	g_nBestMark+=800;
				        if(num_white>num_black)//白 胜
				      	     addp=1;
				         if(num_white<num_black)//黑 胜
					         addp=2;
				        if(num_white==num_black)//平局
						{
					        str1.LoadString(IDS_TIE_CHINESE);
					        win=1;
				 	        addp=3;
						}
			     	   else if((g_bUserBlack && (num_white>num_black)) || ((!g_bUserBlack) && (num_white<num_black)))
					   {
				 	      if(!num_white || !num_black)
						  str1.LoadString(IDS_COMPUTERWIN0_CHINESE);
					      else if(g_nStoneNum>=40)
						  str1.LoadString(IDS_COMPUTERWIN1_CHINESE);
					      else
						  str1.LoadString(IDS_COMPUTERWIN2_CHINESE);
					   }
			     	  else if((g_bUserBlack && (num_white<num_black)) || ((!g_bUserBlack) && (num_white>num_black)))
					  {
					      win=1;
				       	  if(!num_white || !num_black)
					 	  str1.LoadString(IDS_USERWIN0_CHINESE);
					      else if(g_nStoneNum<=6)
						  str1.LoadString(IDS_USERWIN2_CHINESE);
					      else
					 	  str1.LoadString(IDS_USERWIN1_CHINESE);
					  }
   
				       if(num_white!=num_black)
					   {
					      if(num_white && num_black)
						  {
					        	wsprintf(str, str1.GetBuffer(256), g_nStoneNum);
					        	strPrompt=str;
						  }
					   else
					   	strPrompt=str1;
					   }
				       else
				      	strPrompt=str1;	

			            AddStringToList(0,0,0,addp);
			       	    PlaySounds((win==0) ? IDSOUND_COMPUTERWIN : IDSOUND_USERWIN );
                        AfxMessageBox(strPrompt+"    "+str2);//弹出胜负的对话框
			            BOOL bWinner = FALSE;
		          	    if (g_nBestMark>g_nMark1)	    		
	    	       	    bWinner = TRUE;//打破了记录
			        if (bWinner&&(win==1))//存储记录
					{
						 if (g_nSkill == 1)
						 {
	                              g_nTime1 = g_nStoneNum;//棋子的数目
		                          g_nMark1=g_nBestMark;//所得的分数
						 }
	                     else if (g_nSkill == 2)
						 {      
		                     g_nTime2 = g_nStoneNum;
		                     g_nMark2=g_nBestMark;
						 }
	                    if (g_nSkill == 3)
						{		                     
		                      g_nTime3 = g_nStoneNum;
		                      g_nMark3=g_nBestMark;
						}         
					}
					   
			   }//end if(pppp==100)					   		
		             if(m_Skip==1)
					 {
                                     CString str3,str2;
				                     if((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor))
					                 str3.LoadString(IDS_USER_NOPLACE_CHINESE);
				                     else if((g_bUserBlack && m_byColor) || (!g_bUserBlack && !m_byColor))
					                 str3.LoadString(IDS_COMPUTER_NOPLACE_CHINESE);			             
			                         str2.LoadString(IDS_TITLE_CHINESE);
                                     AfxMessageBox(str3+"    "+str2);						 
		                             m_Skip=1;
			                         m_byColor=!m_byColor;
					 }//end  if(m_Skip==1)
		        }//end else
					if(!m_bGameOver && g_bPeepOften)
		            OnCanplace();//显示位置

					if(m_Skip==1)//m_Skip==1表示我无子可走,由对手继续走
					ready=false;//当前用户获得了使用权!!!!m_bGameOver && !m_Skip)
					else
                    ready=true;
					if(m_bGameOver)
					ready=false;
					m_Mutex.Unlock();
			 			           
}

//抄写Ring 的代码






















































































































//本文件共2500行程序